﻿using System.Text;
using Basic.FlowApplication.Interface;
using Basic.FlowApplication.Model;
using Basic.FlowApplication.Model.AuditItem;
using Basic.FlowExtendService;
using Basic.FlowModel.AuditLogItem;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Application.Model;
using Basic.FormRemoteModel.QueryInter.Model;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;

namespace Basic.FlowApplication.Extend
{
    internal class AuditCurrentNodeService : IAuditCurrentNodeService
    {
        private readonly IAuditLogService _AuditLog;
        private readonly IFlowNodeService _Flow;
        private readonly IEmpService _Emp;
        private readonly IFormInterService _Form;
        private readonly ILocalCacheController _Cache;
        public AuditCurrentNodeService ( IFlowAppService flowApp,
            IAuditLogService auditLog,
            IEmpService emp,
            IFlowNodeService flow,
            IFormInterService form,
            ILocalCacheController cache,
            IFlowNextStepService nextStep )
        {
            this._Cache = cache;
            this._Form = form;
            this._Emp = emp;
            this._AuditLog = auditLog;
            this._Flow = flow;
        }

        private NodeItem[] _GetBackNode ( AuditItemLog log, AuditFlowBody flow )
        {
            if ( log.BackNodeId.HasValue )
            {
                FlowNode backNode = flow.Nodes[log.BackNodeId.Value];
                long[] emId = this._AuditLog.GetAuditEmpId(log.LogId, log.RootBatchNo, log.BackNodeId.Value);
                return new NodeItem[]
                {
                    new NodeItem
                    {
                        Id=log.BackNodeId.Value,
                        Name=backNode.NodeName,
                        AuditType=backNode.AuditType,
                        NodeType=backNode.NodeType,
                        EmpId=emId,
                        EmpName=this._Emp.GetName(emId)
                    }
                };
            }
            else
            {
                NodeAuditItem[] items = this._AuditLog.GetBackNode(log.LogId, log);
                if ( !items.IsNull() )
                {
                    if ( log.MarkState == FlowItemMarkState.退回 && log.PrtBatchNo.HasValue )
                    {
                        items = items.Remove(a => a.NodeId == log.NodeId && a.BatchNo != log.PrtBatchNo.Value);
                    }
                    AuditEmpDto[] nodes = items.GroupBy(a => new
                    {
                        a.NodeId,
                        a.BatchNo
                    }).Select(a => new AuditEmpDto
                    {
                        Id = a.Key.NodeId,
                        BatchNo = a.Key.BatchNo,
                        EmpId = a.Select(a => a.EmpId).ToArray()
                    }).Distinct().ToArray();
                    Dictionary<long, string> empName = this._Emp.GetNames(items.Distinct(c => c.EmpId));
                    return nodes.Convert(a =>
                    {
                        FlowNode t = flow.Nodes[a.Id];
                        if ( t.NodeType == FlowNodeType.开始节点 )
                        {
                            return null;
                        }
                        return new NodeItem
                        {
                            Id = t.Id,
                            Name = t.NodeName,
                            EmpId = a.EmpId,
                            AuditType = t.AuditType,
                            NodeType = t.NodeType,
                            BatchNo = a.BatchNo,
                            EmpName = a.EmpId.ConvertAll(b => empName.GetValueOrDefault(b, string.Empty))
                        };
                    });
                }
            }
            return null;
        }
        public AuditNodeLog GetCurentNode ( long itemId, long empId )
        {
            AuditItemLog log = this._AuditLog.GetItem(itemId);
            if ( log.EmpId != empId )
            {
                throw new ErrorException("flow.audit.emp.no.prower");
            }
            AuditFlowBody flow = this._Flow.Get(log.FlowId);
            FlowNode node = flow.Nodes[log.NodeId];
            AuditNodeLog res = new AuditNodeLog
            {
                Id = log.Id,
                LogId = log.LogId,
                DocTitle = log.DocTitle,
                NodeType = log.NodeType,
                LinkType = log.LinkType,
                LinkPk = log.LinkPk,
                EmpId = log.EmpId,
                IsAllowEdit = node.IsAllowEdit,
                AuditOpinion = log.AuditOpinion,
                Status = log.AuditState,
                AuditButton = node.AuditButton,
                OpinionMust = node.OpinionMust,
                AuditType = node.AuditType,
                FlowStatus = FlowLogStatus.待办,
                NodeName = node.NodeName,
                AuditStatus = log.LogAuditStatus,
                IsShowSign = flow.IsShowSign,
                IsSign = node.IsSign,
                IsUpFile = node.IsUpFile,
                IsUpFileSign = node.IsUpFileSign,
                FormId = node.FormId.GetValueOrDefault(flow.DefFormId.Value),
                ColPower = node.ColPower,
            };
            if ( log.LogStatus == FlowAuditLogStatus.已结束 )
            {
                res.FlowStatus = FlowLogStatus.已结束;
            }
            else if ( log.AuditState != FlowAuditItemStatus.审核进行中 && log.AuditState != FlowAuditItemStatus.待开始 )
            {
                res.FlowStatus = FlowLogStatus.已办;
            }
            else if ( log.Status == FlowAuditItemStatus.已作废 || log.Status == FlowAuditItemStatus.已取消 )
            {
                res.FlowStatus = FlowLogStatus.已结束;
            }
            if ( res.FlowStatus == FlowLogStatus.已结束 )
            {
                return res;
            }
            else if ( node.NodeType == FlowNodeType.开始节点 )
            {
                res.AuditButton = FlowAuditButton.审核通过 | FlowAuditButton.取消;
            }
            else
            {
                if ( log.AuditState == FlowAuditItemStatus.审核通过 )
                {
                    long[] nodeId = this._AuditLog.GetRunNodeId(log.LogId, log.RootBatchNo, log.NodeLvl);
                    if ( flow.CheckIsAllowCancel(node, nodeId) )
                    {
                        res.AuditButton |= FlowAuditButton.撤回;
                    }
                }
                if ( ( FlowAuditButton.退回 & node.AuditButton ) == FlowAuditButton.退回 && res.FlowStatus == FlowLogStatus.待办 )
                {
                    res.BackNode = this._GetBackNode(log, flow);
                }
                if ( res.FlowStatus == FlowLogStatus.待办 && !node.Relation.IsNull() )
                {
                    res.FormVal = this._GetFormVal(node, log);
                }
            }
            return res;
        }
        private Dictionary<long, object> _GetFormVal ( FlowNode node, AuditItemLog log )
        {
            string key = "NodeForm_" + log.Id;
            if ( this._Cache.TryGet(key, out Dictionary<long, object> obj) )
            {
                return obj;
            }
            Dictionary<long, FormVal> vals = this._Form.GetFormValues(new FormGetVals
            {
                LinkPK = log.LinkPk,
                LinkType = log.LinkType,
                Cols = node.Relation.ConvertAll(a => new FormCol
                {
                    ColId = a.ColId,
                    FormId = a.FormId,
                    Keywords = a.Keywords
                }),
            });
            obj = node.Relation.ToDictionary(a => a.ToColId, a =>
            {
                if ( vals.TryGetValue(a.ColId, out FormVal val) )
                {
                    return val.FormatValue();
                }
                return null;
            });
            _ = this._Cache.Set(key, obj, DateTime.Now.AddMinutes(30));
            return obj;
        }
    }
}
